#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    Mat src = imread("6.jpg");
    imshow("src", src);

    /* 转灰度图 */
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    imshow("gray", gray);

    /* 高斯模糊降噪，避免环境中的花纹影响边缘检测 */
    Mat blur;
    GaussianBlur(gray, blur, Size(5, 5), 1.0);
    imshow("gaussianBlur", blur);

    /* Canny边缘检测 */
    Mat canny;
    Canny(blur, canny, 20, 100);
    imshow("canny", canny);

    /* 膨胀两次，膨胀是为了让文字连到一块，轮廓数，提高效率，可以按需求调整膨胀的大小 */
    Mat kernel = getStructuringElement(MORPH_RECT, Size(4, 2));
    Mat expand;
    dilate(canny, expand, kernel, Point(-1, -1), 2);
    imshow("dialate", expand);

    /* 检索轮廓 */
    vector<vector<Point>> contours;
    findContours(expand, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    /* 对各个轮廓的旋转角度进行排序 */
    std::vector<float> vecAngles;
    for (int i = 0; i < contours.size(); i++) {
        RotatedRect rr = minAreaRect(contours[i]);
        vecAngles.push_back(rr.angle);
    }
    std::sort(vecAngles.begin(), vecAngles.end());

    /* 以中间值为基准，取相差20%以内的角度的平均值作为结果 */
    float midIndex = int(vecAngles.size() / 2) - 1;
    float midAngle = vecAngles[midIndex];
    float maxAngleThreshold = midAngle > 0 ? midAngle - 15 : midAngle + 15;
    float minAngleThreshold = midAngle > 0 ? midAngle + 15 : midAngle - 15;
    float angleSum = 0;
    int angleCounter = 0;
    cout << "maxAngleThreshold:" << maxAngleThreshold << endl;
    cout << "minAngleThreshold:" << minAngleThreshold << endl;
    for (auto angle : vecAngles) {
        cout << angle << endl;
        if (angle > minAngleThreshold && angle < maxAngleThreshold) {
            angleSum += angle;
            angleCounter++;
        }
    }
    float averageAngle = angleSum / angleCounter;
    cout << "averageAngle:" << averageAngle << endl;
    cout << "midAngle:" << midAngle << endl;

    /* 旋转图像 */
    Mat result;
    Mat rotateM = getRotationMatrix2D(Point2f(gray.cols / 2.0, gray.rows / 2.0), averageAngle, 1.0);
    warpAffine(src, result, rotateM, gray.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(255, 255, 255));
    imshow("result", result);
  	waitKey(0);
}
